package com.firemoss.atonement.changewatcher.observation
{
	import com.firemoss.atonement.changewatcher.valuecomparison.IValueComparitor;
	import com.firemoss.atonement.changewatcher.valuecomparison.IValueComparitorFactory;
	
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	import mx.events.PropertyChangeEvent;
	import mx.events.PropertyChangeEventKind;

	public class ChangeObserver extends EventDispatcher
	{
		private var valueComparitorFactory : IValueComparitorFactory
		private var subject : IEventDispatcher
		private var trackingChanges : Boolean = true
		private var changeList : Array = []

		public function startTrackingChanges() : void
		{
			trackingChanges = true
		}
		
		public function stopTrackingChanges() : void
		{
			trackingChanges = false
		}
		
		public function getPropertyChangeList( clearChanges : Boolean = false ) : Array
		{
			var list : Array = changeList;
			
			if ( clearChanges )
			{
				changeList = []
			}
			
			return list;
		}
		
		public function getPropertyChanges( clearChanges : Boolean = false ) : PropertyChanges
		{
			return new PropertyChanges( getPropertyChangeList( clearChanges ) );
		}
		
		public function ChangeObserver( subject : Object, events : Array, comparitorFactory : IValueComparitorFactory )
		{
			valueComparitorFactory = comparitorFactory;
			
			for each ( var event : String in events )
			{
				subject.addEventListener( event, propertyChanged, false, 0, true );
			}
		}
		
		private function propertyChanged( event : PropertyChangeEvent ) : void
		{
			var oldValue : Object = event.oldValue
			var newValue : Object = event.newValue
			var comparitor : IValueComparitor = valueComparitorFactory.forValues( oldValue, newValue )
			
			var delta : * = comparitor.compare( oldValue, newValue )
				
			if ( delta != null )
			{
				if ( trackingChanges )
				{
					changeList.push( new PropertyChange( event.property.toString(), oldValue, delta ) )
				}
				
				dispatchEvent( new PropertyChangeEvent( PropertyChangeEvent.PROPERTY_CHANGE, false, false, PropertyChangeEventKind.UPDATE, event.property, oldValue, delta, event.target ) );
			}
		}
	}
}